package goquery

import 

type siblingType int

// Sibling type, used internally when iterating over children at the same
// level (siblings) to specify which nodes are requested.
const (
	siblingPrevUntil siblingType = iota - 3
	siblingPrevAll
	siblingPrev
	siblingAll
	siblingNext
	siblingNextAll
	siblingNextUntil
	siblingAllIncludingNonElements
)

// Find gets the descendants of each element in the current set of matched
// elements, filtered by a selector. It returns a new Selection object
// containing these matched elements.
//
// Note that as for all methods accepting a selector string, the selector is
// compiled and applied by the cascadia package and inherits its behavior and
// constraints regarding supported selectors. See the note on cascadia in
// the goquery documentation here:
// https://github.com/PuerkitoBio/goquery?tab=readme-ov-file#api
func ( *Selection) ( string) *Selection {
	return pushStack(, findWithMatcher(.Nodes, compileMatcher()))
}

// FindMatcher gets the descendants of each element in the current set of matched
// elements, filtered by the matcher. It returns a new Selection object
// containing these matched elements.
func ( *Selection) ( Matcher) *Selection {
	return pushStack(, findWithMatcher(.Nodes, ))
}

// FindSelection gets the descendants of each element in the current
// Selection, filtered by a Selection. It returns a new Selection object
// containing these matched elements.
func ( *Selection) ( *Selection) *Selection {
	if  == nil {
		return pushStack(, nil)
	}
	return .FindNodes(.Nodes...)
}

// FindNodes gets the descendants of each element in the current
// Selection, filtered by some nodes. It returns a new Selection object
// containing these matched elements.
func ( *Selection) ( ...*html.Node) *Selection {
	return pushStack(, mapNodes(, func( int,  *html.Node) []*html.Node {
		if sliceContains(.Nodes, ) {
			return []*html.Node{}
		}
		return nil
	}))
}

// Contents gets the children of each element in the Selection,
// including text and comment nodes. It returns a new Selection object
// containing these elements.
func ( *Selection) () *Selection {
	return pushStack(, getChildrenNodes(.Nodes, siblingAllIncludingNonElements))
}

// ContentsFiltered gets the children of each element in the Selection,
// filtered by the specified selector. It returns a new Selection
// object containing these elements. Since selectors only act on Element nodes,
// this function is an alias to ChildrenFiltered unless the selector is empty,
// in which case it is an alias to Contents.
func ( *Selection) ( string) *Selection {
	if  != "" {
		return .ChildrenFiltered()
	}
	return .Contents()
}

// ContentsMatcher gets the children of each element in the Selection,
// filtered by the specified matcher. It returns a new Selection
// object containing these elements. Since matchers only act on Element nodes,
// this function is an alias to ChildrenMatcher.
func ( *Selection) ( Matcher) *Selection {
	return .ChildrenMatcher()
}

// Children gets the child elements of each element in the Selection.
// It returns a new Selection object containing these elements.
func ( *Selection) () *Selection {
	return pushStack(, getChildrenNodes(.Nodes, siblingAll))
}

// ChildrenFiltered gets the child elements of each element in the Selection,
// filtered by the specified selector. It returns a new
// Selection object containing these elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getChildrenNodes(.Nodes, siblingAll), compileMatcher())
}

// ChildrenMatcher gets the child elements of each element in the Selection,
// filtered by the specified matcher. It returns a new
// Selection object containing these elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getChildrenNodes(.Nodes, siblingAll), )
}

// Parent gets the parent of each element in the Selection. It returns a
// new Selection object containing the matched elements.
func ( *Selection) () *Selection {
	return pushStack(, getParentNodes(.Nodes))
}

// ParentFiltered gets the parent of each element in the Selection filtered by a
// selector. It returns a new Selection object containing the matched elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getParentNodes(.Nodes), compileMatcher())
}

// ParentMatcher gets the parent of each element in the Selection filtered by a
// matcher. It returns a new Selection object containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getParentNodes(.Nodes), )
}

// Closest gets the first element that matches the selector by testing the
// element itself and traversing up through its ancestors in the DOM tree.
func ( *Selection) ( string) *Selection {
	 := compileMatcher()
	return .ClosestMatcher()
}

// ClosestMatcher gets the first element that matches the matcher by testing the
// element itself and traversing up through its ancestors in the DOM tree.
func ( *Selection) ( Matcher) *Selection {
	return pushStack(, mapNodes(.Nodes, func( int,  *html.Node) []*html.Node {
		// For each node in the selection, test the node itself, then each parent
		// until a match is found.
		for ;  != nil;  = .Parent {
			if .Match() {
				return []*html.Node{}
			}
		}
		return nil
	}))
}

// ClosestNodes gets the first element that matches one of the nodes by testing the
// element itself and traversing up through its ancestors in the DOM tree.
func ( *Selection) ( ...*html.Node) *Selection {
	 := make(map[*html.Node]bool)
	for ,  := range  {
		[] = true
	}
	return pushStack(, mapNodes(.Nodes, func( int,  *html.Node) []*html.Node {
		// For each node in the selection, test the node itself, then each parent
		// until a match is found.
		for ;  != nil;  = .Parent {
			if [] {
				return []*html.Node{}
			}
		}
		return nil
	}))
}

// ClosestSelection gets the first element that matches one of the nodes in the
// Selection by testing the element itself and traversing up through its ancestors
// in the DOM tree.
func ( *Selection) ( *Selection) *Selection {
	if  == nil {
		return pushStack(, nil)
	}
	return .ClosestNodes(.Nodes...)
}

// Parents gets the ancestors of each element in the current Selection. It
// returns a new Selection object with the matched elements.
func ( *Selection) () *Selection {
	return pushStack(, getParentsNodes(.Nodes, nil, nil))
}

// ParentsFiltered gets the ancestors of each element in the current
// Selection. It returns a new Selection object with the matched elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getParentsNodes(.Nodes, nil, nil), compileMatcher())
}

// ParentsMatcher gets the ancestors of each element in the current
// Selection. It returns a new Selection object with the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getParentsNodes(.Nodes, nil, nil), )
}

// ParentsUntil gets the ancestors of each element in the Selection, up to but
// not including the element matched by the selector. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( string) *Selection {
	return pushStack(, getParentsNodes(.Nodes, compileMatcher(), nil))
}

// ParentsUntilMatcher gets the ancestors of each element in the Selection, up to but
// not including the element matched by the matcher. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return pushStack(, getParentsNodes(.Nodes, , nil))
}

// ParentsUntilSelection gets the ancestors of each element in the Selection,
// up to but not including the elements in the specified Selection. It returns a
// new Selection object containing the matched elements.
func ( *Selection) ( *Selection) *Selection {
	if  == nil {
		return .Parents()
	}
	return .ParentsUntilNodes(.Nodes...)
}

// ParentsUntilNodes gets the ancestors of each element in the Selection,
// up to but not including the specified nodes. It returns a
// new Selection object containing the matched elements.
func ( *Selection) ( ...*html.Node) *Selection {
	return pushStack(, getParentsNodes(.Nodes, nil, ))
}

// ParentsFilteredUntil is like ParentsUntil, with the option to filter the
// results based on a selector string. It returns a new Selection
// object containing the matched elements.
func ( *Selection) (,  string) *Selection {
	return filterAndPush(, getParentsNodes(.Nodes, compileMatcher(), nil), compileMatcher())
}

// ParentsFilteredUntilMatcher is like ParentsUntilMatcher, with the option to filter the
// results based on a matcher. It returns a new Selection object containing the matched elements.
func ( *Selection) (,  Matcher) *Selection {
	return filterAndPush(, getParentsNodes(.Nodes, , nil), )
}

// ParentsFilteredUntilSelection is like ParentsUntilSelection, with the
// option to filter the results based on a selector string. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( string,  *Selection) *Selection {
	return .ParentsMatcherUntilSelection(compileMatcher(), )
}

// ParentsMatcherUntilSelection is like ParentsUntilSelection, with the
// option to filter the results based on a matcher. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( Matcher,  *Selection) *Selection {
	if  == nil {
		return .ParentsMatcher()
	}
	return .ParentsMatcherUntilNodes(, .Nodes...)
}

// ParentsFilteredUntilNodes is like ParentsUntilNodes, with the
// option to filter the results based on a selector string. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( string,  ...*html.Node) *Selection {
	return filterAndPush(, getParentsNodes(.Nodes, nil, ), compileMatcher())
}

// ParentsMatcherUntilNodes is like ParentsUntilNodes, with the
// option to filter the results based on a matcher. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( Matcher,  ...*html.Node) *Selection {
	return filterAndPush(, getParentsNodes(.Nodes, nil, ), )
}

// Siblings gets the siblings of each element in the Selection. It returns
// a new Selection object containing the matched elements.
func ( *Selection) () *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingAll, nil, nil))
}

// SiblingsFiltered gets the siblings of each element in the Selection
// filtered by a selector. It returns a new Selection object containing the
// matched elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingAll, nil, nil), compileMatcher())
}

// SiblingsMatcher gets the siblings of each element in the Selection
// filtered by a matcher. It returns a new Selection object containing the
// matched elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingAll, nil, nil), )
}

// Next gets the immediately following sibling of each element in the
// Selection. It returns a new Selection object containing the matched elements.
func ( *Selection) () *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingNext, nil, nil))
}

// NextFiltered gets the immediately following sibling of each element in the
// Selection filtered by a selector. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNext, nil, nil), compileMatcher())
}

// NextMatcher gets the immediately following sibling of each element in the
// Selection filtered by a matcher. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNext, nil, nil), )
}

// NextAll gets all the following siblings of each element in the
// Selection. It returns a new Selection object containing the matched elements.
func ( *Selection) () *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingNextAll, nil, nil))
}

// NextAllFiltered gets all the following siblings of each element in the
// Selection filtered by a selector. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNextAll, nil, nil), compileMatcher())
}

// NextAllMatcher gets all the following siblings of each element in the
// Selection filtered by a matcher. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNextAll, nil, nil), )
}

// Prev gets the immediately preceding sibling of each element in the
// Selection. It returns a new Selection object containing the matched elements.
func ( *Selection) () *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingPrev, nil, nil))
}

// PrevFiltered gets the immediately preceding sibling of each element in the
// Selection filtered by a selector. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrev, nil, nil), compileMatcher())
}

// PrevMatcher gets the immediately preceding sibling of each element in the
// Selection filtered by a matcher. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrev, nil, nil), )
}

// PrevAll gets all the preceding siblings of each element in the
// Selection. It returns a new Selection object containing the matched elements.
func ( *Selection) () *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingPrevAll, nil, nil))
}

// PrevAllFiltered gets all the preceding siblings of each element in the
// Selection filtered by a selector. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( string) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrevAll, nil, nil), compileMatcher())
}

// PrevAllMatcher gets all the preceding siblings of each element in the
// Selection filtered by a matcher. It returns a new Selection object
// containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrevAll, nil, nil), )
}

// NextUntil gets all following siblings of each element up to but not
// including the element matched by the selector. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( string) *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingNextUntil,
		compileMatcher(), nil))
}

// NextUntilMatcher gets all following siblings of each element up to but not
// including the element matched by the matcher. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingNextUntil,
		, nil))
}

// NextUntilSelection gets all following siblings of each element up to but not
// including the element matched by the Selection. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( *Selection) *Selection {
	if  == nil {
		return .NextAll()
	}
	return .NextUntilNodes(.Nodes...)
}

// NextUntilNodes gets all following siblings of each element up to but not
// including the element matched by the nodes. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( ...*html.Node) *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingNextUntil,
		nil, ))
}

// PrevUntil gets all preceding siblings of each element up to but not
// including the element matched by the selector. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( string) *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingPrevUntil,
		compileMatcher(), nil))
}

// PrevUntilMatcher gets all preceding siblings of each element up to but not
// including the element matched by the matcher. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( Matcher) *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingPrevUntil,
		, nil))
}

// PrevUntilSelection gets all preceding siblings of each element up to but not
// including the element matched by the Selection. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( *Selection) *Selection {
	if  == nil {
		return .PrevAll()
	}
	return .PrevUntilNodes(.Nodes...)
}

// PrevUntilNodes gets all preceding siblings of each element up to but not
// including the element matched by the nodes. It returns a new Selection
// object containing the matched elements.
func ( *Selection) ( ...*html.Node) *Selection {
	return pushStack(, getSiblingNodes(.Nodes, siblingPrevUntil,
		nil, ))
}

// NextFilteredUntil is like NextUntil, with the option to filter
// the results based on a selector string.
// It returns a new Selection object containing the matched elements.
func ( *Selection) (,  string) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNextUntil,
		compileMatcher(), nil), compileMatcher())
}

// NextFilteredUntilMatcher is like NextUntilMatcher, with the option to filter
// the results based on a matcher.
// It returns a new Selection object containing the matched elements.
func ( *Selection) (,  Matcher) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNextUntil,
		, nil), )
}

// NextFilteredUntilSelection is like NextUntilSelection, with the
// option to filter the results based on a selector string. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( string,  *Selection) *Selection {
	return .NextMatcherUntilSelection(compileMatcher(), )
}

// NextMatcherUntilSelection is like NextUntilSelection, with the
// option to filter the results based on a matcher. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( Matcher,  *Selection) *Selection {
	if  == nil {
		return .NextMatcher()
	}
	return .NextMatcherUntilNodes(, .Nodes...)
}

// NextFilteredUntilNodes is like NextUntilNodes, with the
// option to filter the results based on a selector string. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( string,  ...*html.Node) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNextUntil,
		nil, ), compileMatcher())
}

// NextMatcherUntilNodes is like NextUntilNodes, with the
// option to filter the results based on a matcher. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( Matcher,  ...*html.Node) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingNextUntil,
		nil, ), )
}

// PrevFilteredUntil is like PrevUntil, with the option to filter
// the results based on a selector string.
// It returns a new Selection object containing the matched elements.
func ( *Selection) (,  string) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrevUntil,
		compileMatcher(), nil), compileMatcher())
}

// PrevFilteredUntilMatcher is like PrevUntilMatcher, with the option to filter
// the results based on a matcher.
// It returns a new Selection object containing the matched elements.
func ( *Selection) (,  Matcher) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrevUntil,
		, nil), )
}

// PrevFilteredUntilSelection is like PrevUntilSelection, with the
// option to filter the results based on a selector string. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( string,  *Selection) *Selection {
	return .PrevMatcherUntilSelection(compileMatcher(), )
}

// PrevMatcherUntilSelection is like PrevUntilSelection, with the
// option to filter the results based on a matcher. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( Matcher,  *Selection) *Selection {
	if  == nil {
		return .PrevMatcher()
	}
	return .PrevMatcherUntilNodes(, .Nodes...)
}

// PrevFilteredUntilNodes is like PrevUntilNodes, with the
// option to filter the results based on a selector string. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( string,  ...*html.Node) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrevUntil,
		nil, ), compileMatcher())
}

// PrevMatcherUntilNodes is like PrevUntilNodes, with the
// option to filter the results based on a matcher. It returns a new
// Selection object containing the matched elements.
func ( *Selection) ( Matcher,  ...*html.Node) *Selection {
	return filterAndPush(, getSiblingNodes(.Nodes, siblingPrevUntil,
		nil, ), )
}

// Filter and push filters the nodes based on a matcher, and pushes the results
// on the stack, with the srcSel as previous selection.
func filterAndPush( *Selection,  []*html.Node,  Matcher) *Selection {
	// Create a temporary Selection with the specified nodes to filter using winnow
	 := &Selection{, .document, nil}
	// Filter based on matcher and push on stack
	return pushStack(, winnow(, , true))
}

// Internal implementation of Find that return raw nodes.
func findWithMatcher( []*html.Node,  Matcher) []*html.Node {
	// Map nodes to find the matches within the children of each node
	return mapNodes(, func( int,  *html.Node) ( []*html.Node) {
		// Go down one level, becausejQuery's Find selects only within descendants
		for  := .FirstChild;  != nil;  = .NextSibling {
			if .Type == html.ElementNode {
				 = append(, .MatchAll()...)
			}
		}
		return
	})
}

// Internal implementation to get all parent nodes, stopping at the specified
// node (or nil if no stop).
func getParentsNodes( []*html.Node,  Matcher,  []*html.Node) []*html.Node {
	return mapNodes(, func( int,  *html.Node) ( []*html.Node) {
		for  := .Parent;  != nil;  = .Parent {
			 := newSingleSelection(, nil)
			if  != nil {
				if .IsMatcher() {
					break
				}
			} else if len() > 0 {
				if .IsNodes(...) {
					break
				}
			}
			if .Type == html.ElementNode {
				 = append(, )
			}
		}
		return
	})
}

// Internal implementation of sibling nodes that return a raw slice of matches.
func getSiblingNodes( []*html.Node,  siblingType,  Matcher,  []*html.Node) []*html.Node {
	var  func(*html.Node) bool

	// If the requested siblings are ...Until, create the test function to
	// determine if the until condition is reached (returns true if it is)
	if  == siblingNextUntil ||  == siblingPrevUntil {
		 = func( *html.Node) bool {
			if  != nil {
				// Matcher-based condition
				 := newSingleSelection(, nil)
				return .IsMatcher()
			} else if len() > 0 {
				// Nodes-based condition
				 := newSingleSelection(, nil)
				return .IsNodes(...)
			}
			return false
		}
	}

	return mapNodes(, func( int,  *html.Node) []*html.Node {
		return getChildrenWithSiblingType(.Parent, , , )
	})
}

// Gets the children nodes of each node in the specified slice of nodes,
// based on the sibling type request.
func getChildrenNodes( []*html.Node,  siblingType) []*html.Node {
	return mapNodes(, func( int,  *html.Node) []*html.Node {
		return getChildrenWithSiblingType(, , nil, nil)
	})
}

// Gets the children of the specified parent, based on the requested sibling
// type, skipping a specified node if required.
func getChildrenWithSiblingType( *html.Node,  siblingType,  *html.Node,
	 func(*html.Node) bool) ( []*html.Node) {

	// Create the iterator function
	var  = func( *html.Node) ( *html.Node) {
		// Based on the sibling type requested, iterate the right way
		for {
			switch  {
			case siblingAll, siblingAllIncludingNonElements:
				if  == nil {
					// First iteration, start with first child of parent
					// Skip node if required
					if  = .FirstChild;  ==  &&  != nil {
						 = .NextSibling
					}
				} else {
					// Skip node if required
					if  = .NextSibling;  ==  &&  != nil {
						 = .NextSibling
					}
				}
			case siblingPrev, siblingPrevAll, siblingPrevUntil:
				if  == nil {
					// Start with previous sibling of the skip node
					 = .PrevSibling
				} else {
					 = .PrevSibling
				}
			case siblingNext, siblingNextAll, siblingNextUntil:
				if  == nil {
					// Start with next sibling of the skip node
					 = .NextSibling
				} else {
					 = .NextSibling
				}
			default:
				panic("Invalid sibling type.")
			}
			if  == nil || .Type == html.ElementNode ||  == siblingAllIncludingNonElements {
				return
			}
			// Not a valid node, try again from this one
			 = 
		}
	}

	for  := (nil);  != nil;  = () {
		// If this is an ...Until case, test before append (returns true
		// if the until condition is reached)
		if  == siblingNextUntil ||  == siblingPrevUntil {
			if () {
				return
			}
		}
		 = append(, )
		if  == siblingNext ||  == siblingPrev {
			// Only one node was requested (immediate next or previous), so exit
			return
		}
	}
	return
}

// Internal implementation of parent nodes that return a raw slice of Nodes.
func getParentNodes( []*html.Node) []*html.Node {
	return mapNodes(, func( int,  *html.Node) []*html.Node {
		if .Parent != nil && .Parent.Type == html.ElementNode {
			return []*html.Node{.Parent}
		}
		return nil
	})
}

// Internal map function used by many traversing methods. Takes the source nodes
// to iterate on and the mapping function that returns an array of nodes.
// Returns an array of nodes mapped by calling the callback function once for
// each node in the source nodes.
func mapNodes( []*html.Node,  func(int, *html.Node) []*html.Node) ( []*html.Node) {
	 := make(map[*html.Node]bool)
	for ,  := range  {
		if  := (, ); len() > 0 {
			 = appendWithoutDuplicates(, , )
		}
	}
	return 
}